﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using ALinq.BBS.DataAccess.Properties;

namespace ALinq.BBS.DataAccess
{
    public class Replies : IQueryable<Reply>
    {
        private readonly Post post;
        private IQueryable<Reply> source;

        internal Replies(Post post)
        {
            this.post = post;
        }

        IQueryable<Reply> Source
        {
            get
            {
                if (source == null)
                    source = post.DataContext.Replies.Where(o => o.PostID == post.ID);

                return source;
            }
        }

        public ReplyList GetList(int pageIndex)
        {
            Debug.Assert(Settings.Default.ReplyListSize > 1);

            IEnumerable<Reply> items;
            if (pageIndex == 0)
            {
                items = this.Take(Settings.Default.ReplyListSize - 1);
            }
            else
            {
                var num = Settings.Default.ReplyListSize * pageIndex - 1;
                Debug.Assert(num > 0);
                items = this.Skip(num).Take(Settings.Default.ReplyListSize);
            }
            var result = new ReplyList(post, items, pageIndex);
            result.Post = post;
            return result;
        }

        #region Interface
        IEnumerator<Reply> IEnumerable<Reply>.GetEnumerator()
        {
            return Source.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Source.GetEnumerator();
        }

        Expression IQueryable.Expression
        {
            get { return Source.Expression; }
        }

        Type IQueryable.ElementType
        {
            get { return Source.ElementType; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return Source.Provider; }
        }
        #endregion

        internal Database DataContext
        {
            get { return post.Forum.DataContext; }
        }

        public int Count
        {
            get
            {
                return post.RepliesCount;
            }
        }

        public Reply AddItem(string title, string content, string userName)
        {
            var db = this.DataContext;
            db.Connection.Open();
            db.Transaction = db.Connection.BeginTransaction();
            try
            {
                var userID = db.Users.Where(o => o.Name == userName).Select(o => o.ID).Single();
                var id = db.Replies.Max(o => o.ID) + 1;
                var reply = new Reply
                                {
                                    ID = id,
                                    Title = title,
                                    Content = content,
                                    UserName = userName,
                                    UserID = userID,
                                    PostID = post.ID,
                                    Date = DateTime.Now
                                };
                db.Replies.Insert(reply);
                db.Posts.Update(o => new Post { RepliesCount = o.RepliesCount + 1 }, o => o.ID == post.ID);
                db.Forums.Update(o => new Forum { RepliesCount = o.RepliesCount + 1 }, o => o.ID == post.ForumID);

                post.RepliesCount = post.RepliesCount + 1;
                db.Transaction.Commit();

                return reply;
            }
            catch (Exception exc)
            {
                db.Transaction.Rollback();
                throw exc;
            }
            finally
            {
                db.Connection.Close();
            }

        }

        public void UpdateItem(int replyID, string title, string content, string updateBy)
        {
            var db = DataContext;
            db.Connection.Open();
            db.Transaction = db.Connection.BeginTransaction();
            try
            {
                db.Replies.Update(o => new Reply { Title = title, Content = content },
                                  o => o.ID == replyID);
                db.Transaction.Commit();
            }
            catch (Exception exc)
            {
                db.Transaction.Rollback();
                throw exc;
            }
            finally
            {
                db.Connection.Close();
            }
        }

        public int PagesCount
        {
            get
            {
                var config = Settings.Default;
                var num = Convert.ToInt32(Math.Ceiling((float)Count / config.ReplyListSize));
                Debug.Assert(num >= (float)Count / config.ReplyListSize);
                return num;
            }
        }



        public void DeleteItem(int replyID)
        {
            DataContext.Connection.Open();
            DataContext.Transaction = DataContext.Connection.BeginTransaction();
            try
            {
                DataContext.Forums.Update(o => new Forum { RepliesCount = o.RepliesCount - 1 },
                                          o => o.ID == post.ID);

                DataContext.Replies.Delete(o => o.ID == replyID);

                DataContext.Transaction.Commit();

                post.RepliesCount = post.RepliesCount - 1;
            }
            catch (Exception exc)
            {
                DataContext.Transaction.Rollback();
            }
            finally
            {
                DataContext.Connection.Close();
            }
        }
    }
}
